/*
 * OgreFramework.cpp
 *
 *  Created on: 15 Oct 2013
 *      Author: Patrick
 */

#include "OgreFramework.hpp"

using namespace Ogre;

//Needed for the [[Singleton]]
template<> OgreFramework* Ogre::Singleton<OgreFramework>::msSingleton = 0;

/*
 * OgreFramework(): It just sets some default values for the variables
 */
OgreFramework::OgreFramework() {

	m_bShutDownOgre = false;
	m_iNumScreenShots = 0;

	m_pRoot = 0;
	m_pSceneMgr = 0;
	m_pRenderWnd = 0;
	m_pLog = 0;
	m_pTimer = 0;

	m_pTrayMgr = 0;
	m_FrameEvent = Ogre::FrameEvent();

	m_camera = 0;
	m_inputManager = 0;
	m_map = 0;
}

/*
 * initOgre():
 * instantiates the log manager class
 * creates a new Ogre root
 * creates the scene manager and set some ambient light
 * creates the camera and sets its position and clip planes
 * creates the viewport and sets the background color
 * creates the input devices
 * loads the resources
 * creates the timer
 * creates the debug overlay
 * sets the render window active
 */
bool OgreFramework::initOgre(Ogre::String wndTitle) {

	//instantiates the log manager class
	Ogre::LogManager* logMgr = new Ogre::LogManager();

	m_pLog = Ogre::LogManager::getSingleton().createLog("OgreLogfile.log", true,
			true, false);
	m_pLog->setDebugOutputEnabled(true);

	//creates a new Ogre root
	m_pRoot = new Ogre::Root();

	if (!m_pRoot->showConfigDialog())
		return false;
	m_pRenderWnd = m_pRoot->initialise(true, wndTitle);

	//creates the scene manager and set some ambient light
	m_pSceneMgr = m_pRoot->createSceneManager(ST_GENERIC, "SceneManager");
	m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));

	size_t hWnd = 0;
	OIS::ParamList paramList;
	m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd);

	paramList.insert(
			OIS::ParamList::value_type("WINDOW",
					Ogre::StringConverter::toString(hWnd)));

	//create the input manager
	this->m_inputManager = new MyInputManager(paramList, m_pRenderWnd);

	//create the camera
	this->m_camera = new MyCamera(m_pSceneMgr, m_pRenderWnd, m_inputManager);

	//loads the resources
	Ogre::String secName, typeName, archName;
	Ogre::ConfigFile cf;
	cf.load("resources.cfg");

	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
	while (seci.hasMoreElements()) {
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i) {
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
					archName, typeName, secName);
		}
	}
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	//creates the timer
	m_pTimer = new Ogre::Timer();
	m_pTimer->reset();

	//creates the debug overlay
	OIS::Mouse* mouse = this->m_inputManager->GetMouse();
	m_pTrayMgr = new OgreBites::SdkTrayManager("TrayMgr", m_pRenderWnd, mouse,
			this);
	m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
	m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
	m_pTrayMgr->hideCursor();

	//sets the render window active
	m_pRenderWnd->setActive(true);

	//create map
	this->m_map = new GameMap::Map(this->m_inputManager);

	return true;
}

/*
 * ~OgreFramework(): Just clears up the whole thing
 */
OgreFramework::~OgreFramework() {
	delete this->m_inputManager;
	delete this->m_camera;
	delete this->m_map;

	if (m_pTrayMgr)
		delete m_pTrayMgr;
	if (m_pRoot)
		delete m_pRoot;
}

/*
 * updateOgre(): The function will be called by our own demo class in the main loop (so for every frame).
 * It calculates the move and rotation scale in order to take into account the time passed since the last frame.
 * It also calls getInput() and moveCamera() as well as inject an update event into the SdkTrayManager.
 */
void OgreFramework::updateOgre(double timeSinceLastFrame) {

	this->m_camera->updateCamera(timeSinceLastFrame);

	updateTrayMgr(timeSinceLastFrame);
}

bool OgreFramework::isOgreToBeShutDown() const {
	return this->m_inputManager->isKeyDown(OIS::KC_ESCAPE);
}

void OgreFramework::updateTrayMgr(double timeSinceLastFrame) {
	if (this->m_inputManager->isKeyDown(OIS::KC_O)) {
		if (m_pTrayMgr->isLogoVisible()) {
			m_pTrayMgr->hideLogo();
			m_pTrayMgr->hideFrameStats();
		} else {
			m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
			m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
		}
	}

	m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
	m_pTrayMgr->frameRenderingQueued(m_FrameEvent);
}

void OgreFramework::captureInput() {
	this->m_inputManager->captureInput();
}

void OgreFramework::setUpDemoScene() {

	this->m_map->setupDemoScene(this->m_pSceneMgr);
}
